package org.ascollada.core
{
	import org.ascollada.core.ns.collada;
	import org.ascollada.utils.DaeLogger;
	
	public class DaeNode extends DaeElement
	{
		use namespace collada;
		
		public var type :String;
		public var nodes :Array;
		public var transforms :Array;
		public var channels :Array;
		public var geometries :Array;
		public var lights :Array;
		public var cameras :Array;
		public var controllers :Array;

		private var _transformBySID :Object;
		
		/**
		 * 
		 */ 
		public function DaeNode(document:DaeDocument, element:XML=null)
		{
			super(document, element);
		}
		
		/**
		 * 
		 */
		public function getBakedAnimationMatrix(time:Number):DaeMatrix
		{
			var matrix :DaeMatrix = new DaeMatrix();
			var channel :DaeChannel;
			var sampler :DaeSampler;
			var transform :DaeTransform;
			var i :int, j: int;
			
			for each(channel in channels)
			{
				transform = getTransformBySID(channel.targetSID);
				if(!transform || !channel.sampler || !channel.sampler.input)
					return null;
			}
			
			for(i = 0; i < transforms.length; i++)
			{
				transform = transforms[i];
				
				var ch :Array = getChannelsForTransform(transform);
					
				if(ch.length)
				{
					var t :DaeTransform = new DaeTransform(null);
					t.type = transform.type;
					t.data = transform.data.concat();
				
					for(j = 0; j < ch.length; j++)
					{
						channel = ch[j];
						
						var data :Array = channel.getOutputAtTime(time);
						
						switch(t.type)
						{
							case "matrix":
								t.data = data;
								break;
							case "rotate":
								if(channel.targetMember == "ANGLE")
								{
									t.data[3] = data[0];
								}
								break;
							case "scale":
							case "translate":
								switch(channel.targetMember)
								{
									case "X":
										t.data[0] = data[0];
										break;
									case "Y":
										t.data[1] = data[0];
										break;
									case "Z":
										t.data[2] = data[0];
										break;
									default:
										break;
								}
								break;
							default:
								break;
						}
					}	
					matrix.calculateMultiply(matrix, new DaeMatrix(t.toMatrix()));
				}
				else
				{
					matrix.calculateMultiply(matrix, new DaeMatrix(transform.toMatrix()));
				}
			}
			
			return matrix;
		} 
		
		/**
		 * Gets the baked transform.
		 * 
		 * @return The baked transform
		 * 
		 * @see DaeTransform
		 */ 
		public function getBakedTransform():DaeTransform
		{
			var matrix :DaeMatrix = new DaeMatrix();
			var baked :DaeTransform = new DaeTransform(document);
			var transform :DaeTransform;
			var i :int;
			
			for(i = 0; i < transforms.length; i++)
			{
				transform = transforms[i];
				matrix.calculateMultiply(matrix, new DaeMatrix(transform.toMatrix()));
			}
			
			baked.type = "matrix";
			baked.data = matrix.values;
			
			return baked;
		}
		
		/**
		 * 
		 */ 
		public function getChannelsForTransform(transform:DaeTransform):Array
		{
			var result : Array = new Array();
			var channel :DaeChannel;
			
			for(var i:int = 0; i < channels.length; i++)
			{
				channel = channels[i];
				if(channel.targetSID == transform.sid)
					result.push(channel);
			}
			
			return result;	
		}
		
		/**
		 * 
		 */ 
		public function getTransformBySID(sid:String):DaeTransform
		{
			if(_transformBySID.hasOwnProperty(sid))
				return this.transforms[ _transformBySID[sid] ];
			else
				return null;
		}
		
		/**
		 * 
		 */ 
		public function getMorphControllers():Array
		{
			var morphs :Array = new Array();
			var ctrl :DaeInstanceController;
			for(var i:int = 0; i < this.controllers.length; i++)
			{
				ctrl = this.controllers[i];
				if(ctrl.controller && ctrl.controller.morph)
					morphs.push(ctrl.controller);	
			}
			return morphs;	
		}
		
		/**
		 * 
		 */ 
		public function getSkinControllers():Array
		{
			var skins :Array = new Array();
			var ctrl :DaeInstanceController;
			for(var i:int = 0; i < this.controllers.length; i++)
			{
				ctrl = this.controllers[i];
				if(ctrl.controller && ctrl.controller.skin)
					skins.push(ctrl.controller);	
			}
			return skins;	
		}
		
		/**
		 * 
		 */ 
		public override function read(element:XML):void
		{
			super.read(element);
			
			this.type = readAttribute(element, "type") == "JOINT" ? "JOINT" : "NODE";
			this.nodes = new Array();
			this.transforms = new Array();
			this.channels = new Array();
			this.geometries = new Array();
			this.cameras = new Array();
			this.lights = new Array();
			this.controllers = new Array();
			this.name = this.name && this.name.length ? this.name : this.id;

			if(this.document.animatables[id])
			{
				this.channels = this.document.animatables[id];
			}
			
			//DaeLogger.log("[DaeNode id:'" + id + "' name:'" + name + "' sid:'" + sid + "' #channels: " + this.channels.length + "]");
			
			var i :int;
			var children :XMLList = element.children();
			
			for(i = 0; i < children.length(); i++)
			{
				var child :XML = children[i];
				
				switch(child.name().localName)
				{
					case "instance_camera":
						this.cameras.push(new DaeInstanceCamera(this.document, child));
						break;
					case "instance_controller":
						this.controllers.push(new DaeInstanceController(this.document, child));
						break;
					case "instance_geometry":
						this.geometries.push(new DaeInstanceGeometry(this.document, child));
						break;
					case "instance_light":
						this.lights.push(new DaeInstanceLight(this.document, child));
						break;
					case "instance_node":
						this.nodes.push(new DaeInstanceNode(this.document, child));
						break;
					case "node":
						this.nodes.push(new DaeNode(this.document, child));
						break;
					case "matrix":
					case "rotate":
					case "scale":
					case "skew":
					case "lookat":
					case "translate":
						this.transforms.push(new DaeTransform(this.document, child));
						break;
					default:
						break;
				}
			}
			
			_transformBySID = new Object();
			for(i = 0; i < this.transforms.length; i++)
			{
				var transform :DaeTransform = this.transforms[i];
				if(transform.sid && transform.sid.length)
					_transformBySID[transform.sid] = i;	
			}
			
			for(i = 0; i < this.controllers.length; i++)
			{
				var ictrl :DaeInstanceController = this.controllers[i];
				
				if(!ictrl.controller) continue;
					
				if(ictrl.controller.skin)
				{
					var g :DaeInstanceGeometry = new DaeInstanceGeometry(null);
					g.url = ictrl.controller.skin.source;
					g.bindMaterial = ictrl.bindMaterial;
					this.geometries.push(g);
				}
			}
		}
	}
}